#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
// c++中将字符串转化成流
#include <sstream>

#include<fstream>

const static std::string base_sep = "\r\n";
const static std::string line_sep = ": "; 
//前缀路径
const static std::string prefixpath = "wwwroot";
const static std::string homepage = "index.html";
//服务器 HTTP版本
const static std::string httpversion = "HTTP/1.0";

const static std::string space_sep = " ";

const static std::string suffixsep = ".";

const static std::string html_404 = "404.html";


class HttpRequest
{
public:
    HttpRequest() : _blank_line(base_sep), _path(prefixpath)
    {
    }
    // \r\n
    // \r\n data
    std::string Getline(std::string &reqstr)
    {
        auto pos = reqstr.find(base_sep);
        if (pos == std::string::npos)
            return std::string();
        // 注意是前闭后开区间
        // 获取到一行：
        std::string line = reqstr.substr(0, pos);
        // 将一行的内容全部读取（包括"\r\n"
        reqstr.erase(0, line.size() + base_sep.size());
        // 如果读取到的是空行，也就是pos==0, line为空字符串，则说明已经读完报头

        return line.empty() ? base_sep : line;
    }
    void ParseReqLine()
    {
        // 将字符串转化成 字符串流
        std::stringstream ss(_req_line);   // 类似于cin >>
        ss >> _method >> _url >> _version; // 依次按空格为分隔符依次输入多个单词

        _path += _url;
        
        //判断打开的是否是根目录，也就是需要打开默认页
        if(_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        //提取后缀：
        auto pos = _path.find(suffixsep);

        if(pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }


    void ParseReqHeader()
    {
        for (auto &header : _req_headers)
        {
            auto pos = header.find(line_sep);
            if (pos == std::string::npos)
                continue;
            // 注意substr提取到的字符串是左闭右开
            std::string key = header.substr(0, pos);
            std::string val = header.substr(pos + line_sep.size());
            if (key.empty() || val.empty())
                continue;
            _headers_kv.insert(std::make_pair(key, val));
        }
    }

    // 反序列化：
    void Deserialize(std::string &reqstr)
    {
        // A<基本反序列化>
        //  1.获得请求行
        _req_line = Getline(reqstr);
        // 2.获得请求报头
        std::string header;
        do
        {
            header = Getline(reqstr);
            if (header.empty())
                break;
            else if (header != base_sep)
                break;

            _req_headers.push_back(header);

        } while (true);

        // 则说明有正文内容，因此正文内容直接等于剩下的内容
        if (!reqstr.empty())
        {
            _body_text = reqstr;
        }

        // B<进一步反序列化>
        // 解析ReqLine
        ParseReqLine();
        // C<再进一步反序列化>
        ParseReqHeader();
    }

    std::string Url()
    {
        LOG(DEBUG, "Client Want url %s\n", _url.c_str());
        return _url;
    }
    std::string Path()//想要请求的资源的真实路径
    {
        LOG(DEBUG, "Client Want path %s\n", _path.c_str());
        return _path;
    }

    std::string Suffix()//想要请求的资源的真实路径
    {
        return _suffix;
    }

    void Print()
    {
        std::cout << "----------------------------------------------------" << std::endl;
        // 打印请求行
        std::cout << "###" << _req_line << std::endl;
        // 打印请求报头
        for (auto &header : _req_headers)
        {
            std::cout << "@@@" << header << std::endl;
        }
        std::cout << "****" << _blank_line;
        std::cout << ">>>" << _body_text << std::endl;

        std::cout << "Method: " << _method << std::endl
                  << " Url: " << _url << std::endl
                  << "Version" << _version << std::endl;
        for (auto &header_kv : _headers_kv)
        {
            std::cout << ")))" << header_kv.first << "->" << header_kv.second << std::endl;
        }
    }
    ~HttpRequest()
    {
    }

private:
    // 基本的http请求的基本格式
    //  1.请求行
    std::string _req_line;
    // 2.请求报头
    std::vector<std::string> _req_headers;
    // 3.空行
    std::string _blank_line;
    // 4.请求正文内容
    std::string _body_text;

    // 更具体的属性字段，需要进一步反序列化
    std::string _method;
    std::string _url;//--->url是我们要访问的资源，是简化的路径

    std::string _path;//--->将路径拼接好得到完整路径

    std::string _suffix; //资源后缀 
    std::string _version;
    std::unordered_map<std::string, std::string> _headers_kv;
};

class HttpResponse
{
public:
    HttpResponse():_version(httpversion), _blank_line(base_sep)
    {
    }

    void AddCode(int code, const std::string &desc)
    {
        _status_code = code;
        _desc = desc;
    }

    void AddHeader(const std::string &k, const std::string &v)
    {
        //如果key不存在则添加，存在则修改
        _headers_kv[k] = v;

    }

    void AddBodyText(const std::string &body_text)
    {
        _resp_body_text = body_text;
    }

    //序列化请求字符串
    std::string Serialize()
    {   
        //最后将这里得到的字符串return回去给客户端
        // 1.构建状态行
        _status_line = _version + space_sep + std::to_string(_status_code) + space_sep + _desc + base_sep;

        // 2.构建应答报头：
        for(auto &header : _headers_kv)
        {
            std::string header_line = header.first + line_sep + header.second + base_sep;
            _resp_headers.push_back(header_line);
        }

        // 3.空行和正文

        // 4.正式序列化
        std::string responsestr = _status_line;
        for(auto &line : _resp_headers)
        {
            responsestr += line;
        }
        responsestr += _blank_line;
        responsestr += _resp_body_text;
        return responsestr;
    }


    ~HttpResponse()
    {

    }

private:
    //httpresponse的基本属性
    // 1.HTTP版本
    std::string _version;//默认httpversion 1.0
    // 2.状态码
    int _status_code; //默认设置为200
    // 3.状态码描述
    std::string _desc;
    // 4.将来的报头和内容的映射关系，全部都在这里
    std::unordered_map<std::string, std::string> _headers_kv;

    // 基本的http响应基本格式
    //  1.状态行
    std::string _status_line;
    // 2.响应报头
    std::vector<std::string> _resp_headers;
    // 3.空行
    std::string _blank_line;
    // 4.响应正文内容
    std::string _resp_body_text;
};

class HttpServer
{
private:
    //获取请求文件：文件读取操作
    std::string GetFileContent(const std::string &path)
    {   
        //读取必须才用二进制，因为有可能有图片等等
        std::ifstream in(path, std::ios::binary);
        if(!in.is_open()) return std::string();

        in.seekg(0, in.end);//此时读取到了结尾
        int filesize = in.tellg(); //告知我你的rw偏移量是多少，也就是得到文件对应的大小
        //再将读写位置恢复到最开始
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        //这样写会稍微有些破坏字符串的完整性
        in.read((char*)content.c_str(), filesize);
        in.close();
        return content;
    }
public:
    HttpServer()
    {
        _mini_type.insert(std::make_pair(".html", "text/html"));
        _mini_type.insert(std::make_pair(".jpg", "application/x-jpg"));
        _mini_type.insert(std::make_pair(".pdf", "application/pdf"));
        _mini_type.insert(std::make_pair(".gif", "image/gif"));
        _mini_type.insert(std::make_pair(".png", "image/png"));
        _mini_type.insert(std::make_pair(".default", "text/html"));


        _code_desc.insert(std::make_pair(100, "Continue"));
        _code_desc.insert(std::make_pair(200, "OK"));
        _code_desc.insert(std::make_pair(201, "Created"));
        _code_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_desc.insert(std::make_pair(400, "Bad Request"));        
        _code_desc.insert(std::make_pair(401, "Unauthorized"));
        _code_desc.insert(std::make_pair(404, "Not Found"));
        _code_desc.insert(std::make_pair(403, "Forbidden"));

    }
// #define TEST

    std::string HandlerHttpRequest(std::string &reqstr)
    {
#ifdef TEST
        std::cout << "---------------------------------------" << std::endl;
        std::cout << reqstr;
        std::string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n";
        responsestr += "\r\n";
        responsestr += "<html><h1>hxy is a pigpig</h1></html>";
        return responsestr;
#else
      
        std::cout << "---------------------------------------------------"<<std::endl;
        std::cout << reqstr;
        std::cout << "---------------------------------------------------"<<std::endl;
        // 将请求构建成一个结构化请求
        HttpRequest req;
        // 反序列化
        req.Deserialize(reqstr);
        // if(req.Suffix() == ".ico") return std::string();


        // 最基本的上层处理
        HttpResponse resp;
 
        // 打印出反序列化后的结果
        // req.Print();
        std::string content = GetFileContent(req.Path());

        if(content.empty())
        { 
            //文件打开失败,返回一个404的页面就
            std::string content = GetFileContent("wwwroot/404.html");
            resp.AddCode(404, _code_desc[404]);
            resp.AddHeader("Content-Length", std::to_string(content.size()));
            resp.AddHeader("Content-Type", _mini_type[".html"]);
            resp.AddBodyText(content);
        }
        else
        {
            //状态码设置为200
            resp.AddCode(200, _code_desc[200]); 
            //告诉别人请求报头的长度
            resp.AddHeader("Content-Length", std::to_string(content.size()));
            resp.AddHeader("Content-Type", _mini_type[req.Suffix()]);

            resp.AddBodyText(content);
        }
        return resp.Serialize();
#endif
    }

    ~HttpServer()
    {
    }
private:   
    std::unordered_map<std::string, std::string> _mini_type;
    std::unordered_map<int, std::string> _code_desc;
};





